import { SerialCommunicator } from '@/utils/serialSocket'
import { onUnmounted } from 'vue'

let websock: WebSocket | null = null
let agentData = ''
let reconnectTimeout: NodeJS.Timeout | null = null
let reconnectAttempts = 0
const MAX_RECONNECT_ATTEMPTS = 10
const RECONNECT_DELAY = 3000

function isAndroid(): boolean {
  return typeof navigator !== 'undefined' && /Android/i.test(navigator.userAgent)
}

function initWebSocket() {
  if (websock) websock.close()
  const wsUrl = `wss://kd.001155.top:443/websocket`
  try {
    websock = new WebSocket(wsUrl)
    websock.onmessage = handleMessage
    websock.onclose = handleClose
    websock.onopen = handleOpen
    websock.onerror = handleError
    if (isAndroid()) websock.binaryType = 'arraybuffer'
  } catch (error) {
    scheduleReconnect()
  }
}

function handleMessage(event: MessageEvent) {
  let hexCommand: string
  if (event.data instanceof ArrayBuffer) {
    hexCommand = arrayBufferToHexString(event.data)
  } else {
    hexCommand = event.data.toString()
  }
  if (hexCommand.startsWith('resWebsocketCXXOK')) {
    const sbid = hexCommand.split('resWebsocketCXXOK')[0]
    if (sbid === uni.getStorageSync('deviceId')) reconnectAttempts = 0
  } else if (hexCommand.startsWith('openCXX')) {
    const parts = hexCommand.split('openCXX')
    sendHexCommand('openCXX', parts[1], parts[2], parts[3])
  } else if (hexCommand.startsWith('openAllCXX')) {
    const parts = hexCommand.split('openAllCXX')
    sendHexCommand('openAllCXX', parts[1], '', parts[2])
  } else if (hexCommand.startsWith('Heartbeat')) {
    doSend(hexCommand)
  }
  heartCheck.reset().start()
}

function arrayBufferToHexString(buffer: ArrayBuffer): string {
  return Array.from(new Uint8Array(buffer))
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('')
    .toUpperCase()
}

function handleClose(e: CloseEvent) {
  if (e.code !== 1000 && e.code !== 1001) scheduleReconnect()
}

function scheduleReconnect() {
  if (reconnectTimeout) clearTimeout(reconnectTimeout)
  if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
    reconnectAttempts++
    const delay = isAndroid() ? RECONNECT_DELAY * 2 : RECONNECT_DELAY
    reconnectTimeout = setTimeout(initWebSocket, delay)
  }
}

function handleOpen() {
  heartCheck.reset().start()
}

function handleError() {
  if (isAndroid()) {
    if (reconnectTimeout) clearTimeout(reconnectTimeout)
    initWebSocket()
  } else {
    scheduleReconnect()
  }
}

const heartCheck = {
  timeout: isAndroid() ? 10000 : 5000,
  timeoutObj: null as NodeJS.Timeout | null,
  reset() {
    if (this.timeoutObj) clearInterval(this.timeoutObj)
    return this
  },

  start() {
    let checkCount = 0
    this.timeoutObj = setInterval(() => {
      // 检查WebSocket连接状态
      if (websock?.readyState === WebSocket.OPEN) {
        console.info(`WebSocket心跳检测 [${checkCount + 1}] 状态: 正常`)
      } else {
        console.warn(`WebSocket心跳检测 [${checkCount + 1}] 状态: 异常 (状态码: ${websock?.readyState})`)
        // 可以在这里添加重连逻辑
      }
      checkCount++
    }, this.timeout)
  },
}

function sendSock(key: string, callback?: Function) {
  agentData = key
  if (websock?.readyState === WebSocket.OPEN) {
    doSend(key)
  } else if (websock?.readyState === WebSocket.CONNECTING) {
    setTimeout(() => sendSock(agentData, callback), 1000)
  } else {
    initWebSocket()
    setTimeout(() => sendSock(agentData, callback), RECONNECT_DELAY)
  }
}

function doSend(data: string) {
  if (!websock || websock.readyState !== WebSocket.OPEN) return
  if (isAndroid() && data.startsWith('Heartbeat')) {
    const buffer = new TextEncoder().encode(data)
    websock.send(buffer)
  } else {
    websock.send(data)
  }
}

async function sendHexCommand(type: string, bdz: string, sdz: string, sb: string) {
  try {
    const bytes = getBytes16(type, bdz, sdz)
    if (!bytes) return
    await SerialCommunicator.sendData(bytes) // 使用统一串口发送方法，兼容安卓
    doSend(type + 'HDOK' + sb)
  } catch {
    uni.showToast({ title: '串口发送失败', icon: 'none', duration: 2000 })
    doSend(type + 'HDERR' + sb)
  }
}

function getBytes16(type: string, bdz: string, sdz: string) {
  const bdzNum = isNaN(parseInt(bdz, 10)) ? 0 : parseInt(bdz, 10)
  const sdzNum = isNaN(parseInt(sdz, 10)) ? 0 : parseInt(sdz, 10)
  const validBdz = Math.max(0, Math.min(255, bdzNum))
  const validSdz = Math.max(0, Math.min(255, sdzNum))
  if (type === 'openCXX') {
    const toSend = new Uint8Array([0x8a, validBdz, validSdz, 0x11, 0])
    toSend[4] = (toSend[0] ^ toSend[1] ^ toSend[2] ^ toSend[3]) & 0xff
    return toSend
  } else if (type === 'openAllCXX') {
    const toSend = new Uint8Array([0x8a, validBdz, 0xff, 0x11, 0])
    toSend[4] = (toSend[0] ^ toSend[1] ^ toSend[2] ^ toSend[3]) & 0xff
    return toSend
  }
  return null
}

function reconnectWebSocket() {
  reconnectAttempts = 0
  initWebSocket()
}

function closeWebSocket() {
  if (reconnectTimeout) clearTimeout(reconnectTimeout)
  heartCheck.reset()
  if (websock) {
    websock.close(1000, '手动关闭')
    websock = null
  }
}

onUnmounted(closeWebSocket)
// initWebSocket()

export { initWebSocket, sendSock, websock, heartCheck, reconnectWebSocket, closeWebSocket }
